<template>
	<view @touchmove.stop.prevent="() => { return false }">
		<view v-if="show" class="popup-mask" @click="cancel">
			<view class="popup-content" @click.stop>
				<view class="titles">
					<text class="text">{{ popupTitle }}</text>
					<text class="close-btn" @click="cancel">×</text>
				</view>
				<view style="padding: 20rpx 30rpx;">
					<view v-if="showSearch" class="search-box">
						<input v-model="keyword" :maxlength="-1" :placeholder="placeholder" @input="handleSearchInput"
							class="search-input" />
						<view v-if="keyword" class="clear-btn" @click="clearSearch">
							<text class="clear-icon">×</text>
						</view>
					</view>
					<view class="check-tag" v-if="type == 'checkbox'">
						<view class="check-tag-item" v-for="(item, index) in checkboxData" :key="item[valueKey]">
							<text class="check-tag-text">{{ item[nameKey] }}</text>
						</view>
					</view>
				</view>

				<view class="line-gap"></view>

				<view>
					<scroll-view :scroll-top="scrollTop" scroll-y="true" class="scroll-Y" @scrolltolower="$emit('lower')">
						<!--单选-->
						<view v-if="type == 'radio'">
							<view v-for="(item, index) in displayDataLists" :key="item[valueKey]"
								:class="['select-row', { active: radioValue === item[valueKey] }]" @click="handleRadioRowClick(item)"
								style="display: flex; align-items: center;">
								<view class="custom-row">
									<view class="left">
										<view class="custom-radio-icon">
											<view :class="['circle', { checked: radioValue === item[valueKey] }]"></view>
										</view>
										<text class="custom-radio-label">{{ item[nameKey] }}</text>
									</view>
									<view class="right" v-if="showNum">
										<input v-model="item[numKey]" @click.stop type="number" placeholder="请输入"
											@input="handleRadioNumInput($event.detail.value, item)" class="num-input" />
									</view>
								</view>
							</view>
						</view>

						<!--多选-->
						<view v-if="type == 'checkbox'">
							<view v-for="(item, index) in displayDataLists" :key="item[valueKey]"
								:class="['select-row', { active: checkboxValue.includes(item[valueKey]) }]"
								@click="handleCheckboxRowClick(item)" style="display: flex; align-items: center;">
								<view class="custom-row">
									<view class="left">
										<view class="custom-checkbox-icon">
											<view :class="['circle', { checked: checkboxValue.includes(item[valueKey]) }]"></view>
										</view>
										<text class="custom-checkbox-label">{{ item[nameKey] }}</text>
									</view>
									<view class="right" v-if="showNum">
										<input v-model="item[numKey]" @click.stop type="number" placeholder="请输入"
											@input="handleNumInput($event.detail.value, item)" class="num-input" />
									</view>
								</view>
							</view>
						</view>
					</scroll-view>
					<view style="height: 119rpx;"></view>
					<view class="bottons" v-if="type == 'radio'">
						<view class="button-row">
							<view class="button-col">
								<button class="cancel-btn" @click="cancel">取消</button>
							</view>
							<view class="button-col">
								<button class="confirm-btn" @click="submit">确认</button>
							</view>
						</view>
					</view>

					<view class="bottons" v-if="type == 'checkbox'">
						<view class="button-row">
							<view class="check-all-col">
								<view class="check-all">
									<view class="custom-checkbox-icon" @click="toggleCheckAll">
										<view :class="['circle', { checked: checkedAll }]" />
									</view>
									<text @click="toggleCheckAll">全选</text>
									<text class="label">已选<text class="primary-text-color">{{ checkedCount }}</text>项</text>
								</view>
							</view>
							<view class="button-col">
								<button class="confirm-btn" @click="submit">确认</button>
							</view>
						</view>
					</view>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
/**
 * 公共选择下拉框，支持下拉加载、列表搜索、单选｜多选
 * @author Yu
 * @description 弹出层选择器，使用UniApp原生组件实现
 * @property {Array}			dataLists			数据列表
 * @property {String}			nameKey				列表显示的字段名 (默认 'label')
 * @property {String}			numKey				数量字段名 (默认 'num')
 * @property {String}			valueKey			数据项唯一标识字段名 (默认 'value')
 * @property {Boolean}			show				是否展示弹窗 (默认 false)
 * @property {String}			type				选择类型 radio|checkbox (默认 'radio')
 * @property {Boolean}			showSearch			是否显示搜索框 (默认 true)
 * @property {Boolean}			showNum				是否显示数量输入框 (默认 false)
 * @property {String}			popupTitle			列表标题 (默认 '列表选择')
 * @property {String}			placeholder			搜索框placeholder (默认 '请输入搜索内容')
 * @property {Boolean}			isClearable			是否可清空 (默认 false)
 * @property {String|Number|Array}	defaultValue		默认选中值
 * @event {Function} search 搜索事件，返回keyword
 * @event {Function} lower 滑动到底部触发，用于下拉加载新数据
 * @event {Function} cancel 组件关闭事件
 * @event {Function} submit 提交按钮,返回选中的列表数据
 * @example <yu-select :show="show" :popupTitle="popupTitle" @cancel="show=false" @search="selectSearch" nameKey="cworkStationName" numKey="quantity" @submit="onsubmit"
		:dataLists="dataLists" placeholder="输入工站名称搜索"></yu-select>
 */
export default {
	name: "yu-select",
	props: {
		dataLists: {
			default: {},
			type: Array
		},
		nameKey: {
			default: 'label',
			type: String
		},
		numKey: {
			default: 'num',
			type: String
		},
		valueKey: {
			default: 'value',
			type: String
		},
		show: {
			default: false,
			type: Boolean
		},
		type: {
			default: 'radio',
			type: String
		},
		showSearch: {
			default: true,
			type: Boolean
		},
		showNum: {
			default: false,
			type: Boolean
		},
		popupTitle: {
			default: '列表选择',
			type: String
		},
		placeholder: {
			default: '请输入搜索内容',
			type: String
		},
		isClearable: {
			default: false,
			type: Boolean
		},
		defaultValue: {
			default: null,
			type: [String, Number, Array]
		}
	},
	data() {
		return {
			// 搜索关键词
			keyword: '',
			// 滚动条位置
			scrollTop: 0,
			// 多选时已选中的数据项
			checkboxData: [],
			// 多选时已选中的值数组
			checkboxValue: [],
			// 单选时选中的数据项
			radioData: {},
			// 单选时选中的值
			radioValue: '',
			// 所有数据列表的副本
			allDataLists: [],
			// 当前显示的数据列表（经过搜索过滤）
			displayDataLists: []
		};
	},
	created() {
		this.initializeData();
	},
	mounted() {
		this.setDefaultValue();
	},
	watch: {
		dataLists: {
			handler(newVal) {
				if (Array.isArray(newVal)) {
					this.initializeData();
					this.search();
				}
			},
			immediate: true
		},
		defaultValue: {
			handler() {
				this.setDefaultValue();
			},
			immediate: false
		},
		show: {
			handler(newVal) {
				if (newVal) {
					this.scrollTop = 0;
				}
			}
		},
		isClearable: {
			handler(newVal) {
				if (newVal) {
					this.clearAllData();
				}
			}
		}
	},
	computed: {
		checkedCount() {
			return this.checkboxValue.length;
		},
		checkedAll: {
			get() {
				return this.checkboxValue.length === this.allDataLists.length && this.allDataLists.length > 0;
			},
			set(val) {
				if (val) {
					this.checkboxValue = this.allDataLists.map(item => item[this.valueKey]);
				} else {
					this.checkboxValue = [];
				}
			}
		}
	},
	methods: {
		/**
		 * 初始化数据列表
		 * 将传入的数据列表复制到内部变量中
		 */
		initializeData() {
			this.allDataLists = Array.isArray(this.dataLists) ? this.dataLists.slice() : [];
			this.displayDataLists = this.allDataLists.slice();
		},
		/**
		 * 清空所有数据和选择状态
		 * 重置搜索关键词、数量字段和选择状态
		 */
		clearAllData() {
			this.keyword = '';
			if (this.showNum) {
				this.allDataLists.forEach(item => {
					this.$set(item, this.numKey, '');
				});
			}
			if (this.type === 'checkbox') {
				this.checkboxData = [];
				this.checkboxValue = [];
			} else if (this.type === 'radio') {
				this.radioData = {};
				this.radioValue = '';
			}
			this.displayDataLists = this.allDataLists.slice();
		},
		/**
		 * 设置默认选中值
		 * 根据传入的defaultValue设置初始选择状态
		 */
		setDefaultValue() {
			if (!this.defaultValue) return;

			if (this.type === 'checkbox') {
				if (Array.isArray(this.defaultValue)) {
					this.checkboxValue = [...this.defaultValue];
					this.checkboxData = this.allDataLists.filter(item => this.defaultValue.includes(item[this.valueKey]));
				}
			} else if (this.type === 'radio') {
				this.radioValue = this.defaultValue;
				this.radioData = this.allDataLists.find(item => item[this.valueKey] === this.defaultValue) || {};
			}
		},
		/**
		 * 多选状态变化处理
		 * 根据选中的值数组更新多选数据
		 * @param {Array} n 选中的值数组
		 */
		checkboxChange(n) {
			this.checkboxData = this.allDataLists.filter(item => {
				if (this.showNum && n.includes(item[this.valueKey])) {
					if (item && (!item[this.numKey] || Number(item[this.numKey]) <= 0)) {
						this.$set(item, this.numKey, 1);
					}
				}
				return n.includes(item[this.valueKey])
			});
		},
		/**
		 * 全选状态变化处理
		 * @param {Boolean} val 是否全选
		 */
		handleCheckAllChange(val) {
			this.checkedAll = val;
			// 如果是取消全选且显示数量输入框，清空所有数量值
			if (!val && this.showNum) {
				this.allDataLists.forEach(item => {
					this.$set(item, this.numKey, '');
				});
			}
			this.checkboxChange(this.checkboxValue);
		},
		/**
		 * 单选状态变化处理
		 * 根据选中的值更新单选数据
		 * @param {String|Number} n 选中的值
		 */
		groupChange(n) {
			this.radioData = this.allDataLists.find(item => item[this.valueKey] === n) || {};
		},
		/**
		 * 处理搜索输入事件
		 * @param {Object} e 输入事件对象
		 */
		handleSearchInput(e) {
			this.keyword = e.detail.value || '';
			this.search();
		},
		/**
		 * 清除搜索关键词
		 * 重置搜索状态并重新搜索
		 */
		clearSearch() {
			this.keyword = '';
			this.search();
		},
		/**
		 * 执行搜索过滤
		 * 根据关键词过滤数据列表并触发外部搜索事件
		 */
		search() {
			const keyword = String(this.keyword || '').trim();

			this.$emit('search', keyword);

			if (!keyword) {
				this.displayDataLists = this.allDataLists.slice();
				return;
			}

			const kw = keyword.toLowerCase();
			this.displayDataLists = this.allDataLists.filter(item => {
				if (!item || typeof item !== 'object') return false;
				const name = String(item[this.nameKey] || '');
				return name.toLowerCase().includes(kw);
			});
		},
		/**
		 * 取消选择操作
		 * 重置搜索状态并触发取消事件
		 */
		cancel() {
			this.keyword = '';
			this.displayDataLists = this.allDataLists.slice();
			this.$emit('cancel');
		},
		/**
		 * 提交选择结果
		 * 重置搜索状态并触发提交事件
		 */
		submit() {
			this.keyword = '';
			this.displayDataLists = this.allDataLists.slice();

			if (this.type === 'radio') {
				this.$emit('submit', this.radioData);
			} else if (this.type === 'checkbox') {
				this.$emit('submit', this.checkboxData);
			}
		},
		/**
		 * 处理单选项点击事件
		 * 支持点击选中和再次点击取消选中的交互
		 * @param {Object} item 点击的数据项
		 */
		handleRadioRowClick(item) {
			const id = item[this.valueKey];
			if (this.radioValue === id) {
				this.radioValue = '';
				this.radioData = {};
				if (this.showNum) {
					this.$set(item, this.numKey, '');
				}
			} else {
				if (this.showNum && this.radioValue) {
					const prevItem = this.allDataLists.find(i => i[this.valueKey] === this.radioValue);
					if (prevItem) {
						this.$set(prevItem, this.numKey, '');
					}
				}
				this.radioValue = id;
				this.groupChange(id);
				if (this.showNum && (!item[this.numKey] || Number(item[this.numKey]) <= 0)) {
					this.$set(item, this.numKey, 1);
				}
			}
		},
		/**
		 * 处理多选项点击事件
		 * 支持选中和取消选中的切换
		 * @param {Object} item 点击的数据项
		 */
		handleCheckboxRowClick(item) {
			const id = item[this.valueKey];
			let arr = [...this.checkboxValue];
			const i = arr.indexOf(id);
			if (i > -1) {
				arr.splice(i, 1);
				if (this.showNum) {
					this.$set(item, this.numKey, '');
				}
			} else {
				arr.push(id);
				if (this.showNum && (!item[this.numKey] || Number(item[this.numKey]) <= 0)) {
					this.$set(item, this.numKey, 1);
				}
			}
			this.checkboxValue = arr;
			this.checkboxChange(arr);
		},
		/**
		 * 处理多选数量输入事件
		 * 根据输入的数量自动选中或取消选中项目
		 * @param {String} val 输入的数量值
		 * @param {Object} item 对应的数据项
		 */
		handleNumInput(val, item) {
			if (!this.showNum) return;

			const num = Number(val) || 0;
			const id = item[this.valueKey];
			const index = this.checkboxValue.indexOf(id);

			if (num > 0) {
				if (index === -1) {
					this.checkboxValue.push(id);
					this.checkboxChange(this.checkboxValue);
				}
			} else {
				if (index > -1) {
					this.checkboxValue.splice(index, 1);
					this.checkboxChange(this.checkboxValue);
				}
			}
		},
		/**
		 * 处理单选数量输入事件
		 * 根据输入的数量自动选中或取消选中项目
		 * @param {String} val 输入的数量值
		 * @param {Object} item 对应的数据项
		 */
		handleRadioNumInput(val, item) {
			if (!this.showNum) return;

			const num = Number(val) || 0;
			const id = item[this.valueKey];

			if (num > 0) {
				if (this.radioValue && this.radioValue !== id) {
					const prevItem = this.allDataLists.find(i => i[this.valueKey] === this.radioValue);
					if (prevItem) {
						this.$set(prevItem, this.numKey, '');
					}
				}
				this.radioValue = id;
				this.groupChange(id);
			} else {
				if (this.radioValue === id) {
					this.radioValue = '';
					this.radioData = {};
				}
			}
		},
		/**
		 * 切换全选状态
		 * 在全选和全不选之间切换
		 */
		toggleCheckAll() {
			const newValue = !this.checkedAll;
			this.checkedAll = newValue;
			this.handleCheckAllChange(newValue);
		}
	}
}
</script>

<style lang="scss" scoped>
// 主题色配置
$primary-color: #2B8BE4;
$primary-light: #EBF5FD;
$primary-text: #0076F9;

.popup-mask {
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	background-color: rgba(0, 0, 0, 0.5);
	z-index: 999;
	display: flex;
	align-items: flex-end;
}

.popup-content {
	background-color: white;
	width: 100%;
	max-height: 80vh;
	border-radius: 20rpx 20rpx 0 0;
	overflow: hidden;
}

.search-box {
	position: relative;
	display: flex;
	align-items: center;
	background-color: #F8F8F8;
	border: 1rpx solid #E5E5E5;
	border-radius: 25rpx;
	box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
	transition: all 0.3s ease;
	height: 86rpx;
	box-sizing: border-box;
}

.search-box:focus-within {
	border-color: $primary-color;
	box-shadow: 0 2rpx 12rpx rgba(43, 139, 228, 0.15);
}

.search-input {
	flex: 1;
	height: 86rpx;
	border: none;
	outline: none;
	padding: 0 70rpx 0 30rpx;
	box-sizing: border-box;
	font-size: 28rpx;
	background-color: transparent;
	color: #333;
	line-height: 86rpx;
}

.search-input::placeholder {
	color: #999;
	font-size: 28rpx;
}

.clear-btn {
	position: absolute;
	right: 20rpx;
	top: 50%;
	transform: translateY(-50%);
	width: 40rpx;
	height: 40rpx;
	display: flex;
	align-items: center;
	justify-content: center;
	background-color: #ddd;
	border-radius: 50%;
	transition: all 0.2s ease;
	/* #ifdef H5 */
	cursor: pointer;
	/* #endif */
}

.clear-btn:active {
	transform: scale(0.95);
	background-color: #ccc;
}

.clear-icon {
	font-size: 28rpx;
	color: #fff;
	font-weight: bold;
	line-height: 1;
}

.num-input {
	height: 60rpx;
	border: 1rpx solid #E5E5E5;
	border-radius: 8rpx;
	padding: 0 15rpx;
	box-sizing: border-box;
	font-size: 28rpx;
	text-align: center;
	width: 120rpx;
}

.button-row {
	display: flex;
	align-items: center;
	padding: 20rpx;
	/* #ifdef MP-WEIXIN || H5 */
	gap: 20rpx;
	/* #endif */
	/* #ifndef MP-WEIXIN */
	/* #ifndef H5 */
	justify-content: space-between;
	/* #endif */
	/* #endif */
}

.button-col {
	flex: 1;
	/* #ifndef MP-WEIXIN */
	/* #ifndef H5 */
	margin-left: 20rpx;
	/* #endif */
	/* #endif */
}

.check-all-col {
	flex: 2;
	/* #ifndef MP-WEIXIN */
	/* #ifndef H5 */
	margin-right: 20rpx;
	/* #endif */
	/* #endif */
}

.cancel-btn {
	height: 80rpx;
	border: 1rpx solid #E5E5E5;
	border-radius: 40rpx;
	background-color: white;
	color: #333;
	font-size: 30rpx;
	line-height: 80rpx;
}

.confirm-btn {
	height: 80rpx;
	border: none;
	border-radius: 40rpx;
	background-color: $primary-color;
	color: white;
	font-size: 30rpx;
	line-height: 80rpx;
}

.cancel-btn::after,
.confirm-btn::after {
	border: none;
}

.titles {
	height: 100rpx;
	width: 100%;
	border-bottom: 1rpx solid #ECECEE;
	padding: 20rpx;
	font-family: PingFang SC;
	font-weight: 500;
	font-size: 30rpx;
	color: #1D2129;
	position: relative;
	/* #ifdef H5 */
	-webkit-user-select: none;
	user-select: none;

	/* #endif */
	.text {
		position: absolute;
		left: 50%;
		top: 50%;
		transform: translate(-50%, -50%);
	}

	.close-btn {
		position: absolute;
		right: 40rpx;
		top: 50%;
		transform: translateY(-50%);
		font-size: 44rpx;
		color: #A9A9A9;
		font-weight: bold;
		/* #ifdef H5 */
		cursor: pointer;
		/* #endif */
	}
}

.scroll-Y {
	height: 550rpx;
}

.bottons {
	background-color: white;
	position: fixed;
	left: 0;
	bottom: 0;
	right: 0;
	// /* #ifdef APP-PLUS || MP-WEIXIN */
	// bottom: constant(safe-area-inset-bottom);
	// bottom: env(safe-area-inset-bottom);
	// /* #endif */
	border-top: 1rpx solid #ECECEE;
	z-index: 99999;
}

.check-all {
	display: flex;
	align-items: center;
	font-family: PingFang SC;
	font-weight: 500;
	font-size: 30rpx;
	color: #333333;
	height: 80rpx;

	.label {
		margin-left: 20rpx;
	}
}

.check-tag {
	display: flex;
	flex-wrap: wrap;

	.check-tag-item {
		display: flex;
		justify-content: center;
		align-items: center;
		height: 48rpx;
		background: $primary-light;
		border-radius: 24rpx;
		font-family: PingFang SC;
		font-weight: bold;
		font-size: 24rpx;
		color: $primary-text;
		padding: 0 22rpx;
		margin-right: 10rpx;
		margin-top: 20rpx;
	}
}

.line-gap {
	height: 8rpx;
	background: #F5F6F7;
}

.select-row {
	border-bottom: 1rpx solid #DDE3E8;
	/* #ifdef H5 */
	cursor: pointer;
	/* #endif */
}

.select-row.active {
	background: $primary-light;
}

.custom-radio-icon,
.custom-checkbox-icon {
	width: 40rpx;
	height: 40rpx;
	display: flex;
	align-items: center;
	justify-content: center;
	margin-right: 10rpx;
	/* #ifdef H5 */
	cursor: pointer;
	/* #endif */
}

.circle {
	width: 32rpx;
	height: 32rpx;
	border-radius: 50%;
	border: 2rpx solid #bbb;
	background: #fff;
	box-sizing: border-box;
}

.circle.checked {
	border: 2rpx solid $primary-color;
	background: $primary-color;
	position: relative;
}

.circle.checked::after {
	content: '';
	display: block;
	width: 8rpx;
	height: 18rpx;
	border: solid #fff;
	border-width: 0 4rpx 4rpx 0;
	position: absolute;
	left: 50%;
	top: 50%;
	transform: translate(-50%, -60%) rotate(45deg);
	background: none;
}

.custom-radio-label,
.custom-checkbox-label {
	font-size: 28rpx;
	color: #333;
}

.primary-text-color {
	color: $primary-text;
}

.custom-row {
	display: flex;
	align-items: center;
	width: 100%;

	.left {
		flex: 1;
		display: flex;
		align-items: center;
		padding: 30rpx;
	}

	.right {
		font-size: 28rpx;
		max-width: 240rpx;
		text-align: center;
		padding: 30rpx;
		border-left: 1rpx solid #E5E5E5;
	}
}
</style>